﻿//
// Created by LiuYou on 2021/4/10.
//
#include <stdio.h>
#include <string.h>

/**
 * @brief 字符串处理函数
 *
 */
void other4() {
    char* str = "I love C/C++ forever!";
    printf("%d\n", strlen(str));
    const char* str2 = " yes! ";
//    strcat(str, str2);
//    printf("%s\n", str);
    // 调用strcat函数后原来的字符串在静态存储区自身改变了！变为 I love C/C++ forever! yes! 。
    // 之前的I love C/C++ forever!没有了。这里要注意！而且这样没有定义数组而使用指针的不安全！
    // 所以尽量定义数组在非静态存储区进行字符串处理！！！！
    printf("%s\n", strcat(str, str2));
    printf("%s\n", str);
    printf("%d\n", strlen(str));
    printf("%s\n", str2);

}

/**
 * @brief 字符串
 * 用双引号括起来的内容称为字符串字面值(string literal)，也叫做字符串常量(string constant)。
 * 字符串常量(字符串字面值)输入静态存储类别(static storage class)，这说明在函数中使用字符串字面值，该字符串只会被存储一次，
 * 在整个程序的生命期内都存在。
 *
 *      const char* ptr = "I love C/C++ forever!";  // length = 21
 *      const char arr[] = "I love C/C++ forever!";
 *      以上两种都定义了两个字符串。但是是有区别的！
 *      TODO 注意: 带双引号的字符串本身就决定了在内存的静态存储区已经预留给了该字符串存储空间。(就是该字符串字面值已经在内存的静态存储区中存储了！)
 *      区别:
 *          数组形式在计算机的内存中分配一个22个元素的字符数组(包括了最后的 '\0')。数组形式的字符串在为数组分配内存后，此时内存中是有
 *          两个相同的字符串的。一个在内存得到静态存储区中的字符串字面值，另一个是存储在arr[]数组中的字符串。
 *          TODO 注意: 初始化数组把静态存储区的字符串拷贝到数组中，而初始化指针只把字符串的地址拷贝给指针！！！！
 *          初始化字符数组来存储字符串和初始化指针来指向字符串还有一个区别是数组名是地址常量，指针是变量。
 *          两者都可以使用数组表示法，都能进行指针加法操作，但是只有指针可以进行自增操作。但是当指针指向别处时，就无法访问该字符串了，除非再指回该字符串。
 *          如果要用数组表示一系列待显示的字符串，请使用指针数组，因为它比二维字符数组的效率高。但是，指针数组也有自身的缺点。
 *          如果要改变字符串或为字符串输入预留空间，不要使用指向字符串字面值的指针。
 *
 */
void other3() {
    char word1[] = "love";
    // 可以
    word1[1] = 'a';

    char* word2 = "love";
    // 不行。这是错误的，是未定义的行为。其实就是错误。但是编译器不会报错！！！！所以怎么做更好？加const。
    word2[1] = 'a';

    const char* word3 = "love";
    // 注意: 此时会报错。这样写代码更加严谨。
//    word3[1] = 'a';

}

/**
 * @brief 输入输出(IO函数)和缓冲区
 * 缓冲区:
 *      大部分系统在用户按下Enter键之前不会重复打印刚输入的字符，这种输入形式属于缓冲输入。
 *      用户输入的字符被收集并存储在一个被称为缓冲区(buffer)的临时存储区，按下Enter键后，程序才可以使用用户输入的字符。
 *
 *      为什么要有缓冲区？
 *          首先，把若干字符作为一个块进行传输比逐个发送这些字符节约时间。
 *          其次，如果用户打错字符，可以直接通过键盘修正错误。当最后按下Enter键时，传输的是正确的输入。
 *
 *          虽然缓冲输入好处很多，但是某些交互式程序也需要无缓冲输入。例: 在游戏中，你希望按下一个键就执行相应的指令。
 *          因此，缓冲输入和无缓冲输入都有用武之地。
 *
 *          缓冲分为两类:
 *              * 完全缓冲I/O 指的是当缓冲区被填满时才刷新缓冲区(内容被发送到目的地, 例如文件)，通常出现在文件中。
 *              缓冲区的大小取决于操作系统，常见的大小是512字节和4096字节。随着计算机硬盘容量越来越大，缓冲区的大小也越来越大。
 *              * 行缓冲I/O 指的是在出现换行符时刷新缓冲区。键盘输入通常是行缓冲输入，所以在按下Enter键后才刷新缓冲区。
 *              注意: ANSI C和后续的C标准都规定输入是缓冲的，输入一定是缓冲的！
 *
 * C语言程序处理的是流而不是直接处理文件。C把输入和输出设备视为存储设备上的普通文件，尤其是把键盘和显示设备视为每个C程序自动打开的文件。
 * stdin流表示键盘输入，stdout流表示屏幕输出。I/O函数(如: printf/scanf等)来处理这两个流。
 *
 * 在C语言中读取文件检测到文件结尾时将返回一个特殊的值: EOF(end of file)。
 * source code:
 *      #define EOF (-1)
 * 为什么是-1？
 * 因为0~127这些值对应标准字符集。如果在0~127之后也是对应了其它的扩展字符。无论哪种情况，-1都不对应任何字符，所以可以标记文件结尾。
 *
 * 输入是缓冲输入，而且一定是缓冲输入，而且这也是C的一个标准。在把输入发送给程序之前，用户可以编辑输入。但是也有麻烦: 缓冲输入要求
 * 按下Enter键发送输入。而且通常系统的键盘输入是行缓冲输入，按下Enter键的同时也传送了一个换行符，编程时要注意处理这个换行符！
 *
 * 指针的下标表示法
 *      在C语言中 a[i] 和 *(a+1) 这两个表达式是等价的！
 *      无论 a 是数组名还是指针变量。
 *      但是只有当 a 是指针变量时才能 ++a / a++ 这种表达式。因为数组名是一个地址常量，不能改变自身(所以不能自增自减，但是可以进行 a + i /
 *      a + 1 / a + 2 / ... / a - 2 等不改变自身值的算术运算！)。
 *
 */
void other2() {


}

/**
 * @brief sizeof和size_t
 * C语言规定: sizeof返回size_t类型的值。size_t是一个无符号整型(unsigned int)。
 *
 * C语言把所有非零的值都视为真。零为假。
 *
 * 循环辅助: continue 和 break
 */
void other1() {

}

int main() {
//    other3();

    other4();


    return 0;
}